#include "net.h"
#include <QBitArray>
#include <QDebug>

/** Очистить.*/
inline void Net::clear(){
	IsInit = false;
	imgs->clear();
	chars.clear();
	// из условия 0 < e < 1/m было решено взять e=1/2m
	e = 1.0/(2*QuantityNeurons);
	T = (double)(RowCount * ColumnCount) / 2;
	F = 0.25 * QuantityNeurons;
	MaxIter = 5 * QuantityNeurons;
}

Net::Net(int rowCount, int columnCount, int quantityNeurons, QObject *parent) :
	QObject(parent),
	RowCount(rowCount),
	ColumnCount(columnCount),
	IsInit(false),
	QuantityNeurons(quantityNeurons),
	imgs(new QList<QBitArray >()){
	clear();
}

Net::~Net(){
	delete imgs;
}

/** Инициализация сети переданными картинками.*/
inline void Net::init(){
	w1.clear();
	for (int i = 0; i < QuantityNeurons; ++i){
		w1.append(QVector<double>());
		for(int j = 0; j < RowCount * ColumnCount; ++ j)
			w1[i].append( (double)(imgs->at(i).at(j)) / 2 );
		qDebug()<<trUtf8("Кол-во синапсов в одном нейроне первого слоя %1").arg(w1.at(i).size());
		qDebug()<<w1.at(i);
	}
	qDebug()<<trUtf8("Кол-во нейронов первого слоя %1").arg(w1.size());
}

/** Кол-во строк в матрице.*/
int Net::rowCount() const{
	return RowCount;
}

/** Кол-во столбцов в матрице.*/
int Net::columnCount() const{
	return ColumnCount;
}

/** Задать кол-во строк в матрице.*/
void Net::setRowCount(int n){
	RowCount = n;
	clear();
}

/** Задать кол-во столбцов в матрице.*/
void Net::setColumnCount(int n){
	ColumnCount = n;
	clear();
}

/** Передано необходимое кол-во картинок или нет.*/
bool Net::isInit() const{
	return IsInit;
}

/** Кол-во нейронов.*/
int Net::quantityNeurons() const{
	return QuantityNeurons;
}

/** Задать кол-во нейронов.*/
void Net::setQuantityNeurons(int n){
	QuantityNeurons = n;
	clear();
}

/**Добавить картинку.*/
void Net::addImage(const QBitArray & img, const QChar c){
	if(IsInit);else{ // Если не все картинки заполнены.
		imgs->append(img);
		chars.append(c);
		if(imgs->size() == QuantityNeurons){
			IsInit = true;
			init();
		}
	}
}


/** Найти наиболее подходящий символ.*/
QChar Net::inquire(const QBitArray & img){
////Вычисляю аксоны первого слоя//////////////////////////////////////////////////////////////////
	y1.clear();
	double sum;
	for(int i = 0; i < QuantityNeurons; ++i){
		sum = 0;
		for(int j = 0; j < RowCount * ColumnCount; ++ j)
			sum += w1.at(i).at(j) * img.at(j);
		y1.append(sum + T);
	}
	qDebug()<<trUtf8("Кол-во аксонов первого слоя %1").arg(y1.size());
	qDebug()<<y1;
////После этого полученными значениями инициализируются значения аксонов второго слоя////////////
	y2 = y1;
////Расчитываю новые значения аксонов второ слоя пока их значения не перестанут изменяться.////////////
	bool flag; // Равны ли новые и старые значения аксонов второ слоя;
	double buff;
	int i = 0;
	for(int i = 0; i < MaxIter; ++i ){ // Цикл ограничен, чтоб не стать бесонечным, внутри есть условие выхода при одинаковых новых и старых значениях.
//---Вычислить новые состояния нейронов второго слоя--------------------------------------
		s2.clear();
		for(int i = 0; i < QuantityNeurons; ++i){
			sum = 0;
			for(int j = 0; j < QuantityNeurons; ++ j)
				if(j != i)
					sum += y2.at(j);
			s2.append(y2.at(i) - e * sum);
		}
		qDebug()<<trUtf8("Кол-во нейронов второго слоя %1").arg(s2.size());
		qDebug()<<s2;
//---Вычислить новые значения аксонов второго слоя-----------------------------------------
		flag = true;
		for(int i = 0; i < QuantityNeurons; ++i){
			buff = s2.at(i)>F?s2.at(i):0;
			flag &= (buff == y2[i]);
			y2[i] = buff;
		}		
		qDebug()<<trUtf8("Кол-во аксонов второго слоя %1").arg(y2.size());
		qDebug()<<y2;
	++i;
	qDebug()<<flag;
	// Если значения аксонов второ слоя не изменились, выхожу из цикла.
	if(flag)
		break;
	}

////Найду максим.  выход////////////////////////////////////////////////////////////////////////////////////
	int n = 0;
	double rez = y2.at(n);
	flag = true;
	for(int i = 1; i < QuantityNeurons; ++i){
		if(y2.at(i) > rez){
			rez = y2.at(i);
			n = i;
		}
		flag &= (y2.at(i) == y2.at(i - 1));
	}
	qDebug()<<y2;
	qDebug()<<n;
	if(flag)
		return '?';
	else
		return chars.at(n);
}
